import java.util.*;
public class Data
{
	public static final int TRUCK_COST[] = {4800,6300,7900};
	public static final int TRUCK_CAPACITY[] = {200,250,320};
	public static final int TOTAL_BUILDINGS = 50;
	public static final double SLACK_PROPORTION = 1.1d; 
	public static final double INF = Long.MAX_VALUE; 
	public static final int CHROMOSOME_SIZE = 50+7+7*(4+4+4);
	public static final double EPS = 1E-20;
	public static final double CROSSOVER_PROBABILITY = 0.95D;
	public static final double MUTATION_PROBABILITY = 1D/(double)CHROMOSOME_SIZE;
	
	public static int POPULATION_COUNT = 500;//must be even
	public static int TOTAL_ITERATIONS = 100;
	
	
	private static double[][] biologicalRiskGarbage;
	private static double[][] normalGarbage;	
	private static double[][] matrix;
	
	public static double[][] getBiologicalRiskGarbageMatrix()
	{
		return Data.biologicalRiskGarbage;
	}
	public static double[][] getNormalGarbageMatrix()
	{
		return Data.normalGarbage;
	}
	public static void readData()throws Exception
	{
		biologicalRiskGarbage = Util.readMatrix( TOTAL_BUILDINGS, 7, "biological_risk.txt");
		normalGarbage = Util.readMatrix( TOTAL_BUILDINGS, 7, "normal_garbage.txt");
	}
	public static void printNormalGarbageMatrix()
	{
		Util.printMatrix(normalGarbage);
	}
	public static void printBiologicalRiskGarbageMatrix()
	{
		Util.printMatrix(biologicalRiskGarbage);
	}	
	public static Chromosome getRandomChromosome()
	{
		BitSet bitset = new BitSet(CHROMOSOME_SIZE);
		for (int index = 0; index < Data.TOTAL_BUILDINGS+7; index++)
			bitset.set(index , Random.getRandomBoolean(0.5));		
		/*
		for (int index = Data.TOTAL_BUILDINGS+7; index < CHROMOSOME_SIZE; index++)
		{
			boolean value = Random.getRandomBoolean(0.3);
			bitset.set(index , value );
		}
		*/
		Set<Boolean> values = new TreeSet<Boolean>();
		for (int index = Data.TOTAL_BUILDINGS,d = 0; d < 7; ++d,index++)
			values.add( bitset.get(index) ) ;
		
		if( values.size() == 1 )
		{
			bitset.flip(Data.TOTAL_BUILDINGS+3);
			bitset.flip(Data.TOTAL_BUILDINGS+4);
		}
		Chromosome chromosome = new Chromosome(bitset);
		Fenotipe fenotipe = chromosome.getFenotipe();
		HashSet<Integer> recolectDaysGroupOne = new HashSet<Integer>();
		HashSet<Integer> recolectDaysGroupTwo = new HashSet<Integer>();
		for (int day = 0; day < 7; day++)
		{
			int dayGroup = ((1<<day)&fenotipe.getDayMask()) == 0 ? 0 : 1;							
			if( dayGroup == 0 )recolectDaysGroupOne.add(day);			//set 0
			else recolectDaysGroupTwo.add(day);// set 1
		}
		HashMap<Integer,HashSet<Integer> > m = fenotipe.getDayMap(recolectDaysGroupOne, recolectDaysGroupTwo);
		
		double garbageAccum[] = new double[7];
		double matrix[][] = Data.getMatrix();
		
		for (int building = 0; building < matrix.length; building++)
			for (int day = 0; day < 7; day++)
				for (int dc : m.get(day))
					garbageAccum[day] += matrix[building][dc]*Data.SLACK_PROPORTION;
		
		int trucks[][] = new int[7][3];
		//double garbageCapacityAccum[] = getGarbageCapacityAccum(trucks);
		double garbageCapacityAccum[] = new double[7];
		for (int day = 0; day < 7; day++)
			for (int truckType = 0; truckType < 3; truckType++)
				garbageCapacityAccum[day] += Data.TRUCK_CAPACITY[truckType] * trucks[day][truckType];
		//return garbageCapacityAccum;
		while( !isAvailable(garbageAccum,garbageCapacityAccum) )
		{
			int day = 0;
			int truckType = 0;
			do
			{
				day = Random.getRandomNumber(0, 100)%7;
				truckType = Random.getRandomNumber(0, 100)%3;
			}while( trucks[day][truckType] == 15 );
			
			if( garbageCapacityAccum[day] >= garbageAccum[day] )continue;
				
			++trucks[day][truckType];
				
			//garbageCapacityAccum[day] += Data.TRUCK_CAPACITY[ truckType ];
			
			//System.out.println(Arrays.deepToString(trucks));
			//garbageCapacityAccum = getGarbageCapacityAccum(trucks);
			
			Arrays.fill(garbageCapacityAccum, 0);
			for (int day2 = 0; day2 < 7; day2++)
				for (int truckType2 = 0; truckType2 < 3; truckType2++)
					garbageCapacityAccum[day2] += Data.TRUCK_CAPACITY[truckType2] * trucks[day2][truckType2];
			//return garbageCapacityAccum;
		}
				
		int index = Data.TOTAL_BUILDINGS+7;
		for (int day = 0; day < 7; day++)
		{
			for (int truckType = 0; truckType < 3; truckType++)
			{
				String s = Integer.toBinaryString(trucks[day][truckType]);
				while( s.length() < 4 )s = "0"+s;
				s = new StringBuilder(s).reverse().toString();
				//System.out.println(trucks[day][truckType]+" <-> "+s);
				for (int i = 0; i < 4; i++,++index)
					bitset.set(index,s.charAt(i) == '1');
			}
		}
		return new Chromosome(bitset);
	}
	private static double[] getGarbageCapacityAccum(int[][] trucks)
	{
		double garbageCapacityAccum[] = new double[7];
		for (int day = 0; day < 7; day++)
			for (int truckType = 0; truckType < 3; truckType++)
				garbageCapacityAccum[day] += Data.TRUCK_CAPACITY[truckType] * trucks[day][truckType];
		return garbageCapacityAccum;
	}
	private static boolean isAvailable(double[] garbageAccum, double[] garbageCapacityAccum) {
		for (int i = 0; i < 7; i++)
			if( garbageAccum[i] > garbageCapacityAccum[i] )
				return false;		
		return true;
	}
	public static double[][] getMatrix()
	{
		return matrix;
	}
	public static void setMatrix( final double[][] m )
	{
		matrix = m;
	}
	public static void setPopulation(int population)
	{
		Data.POPULATION_COUNT = population;		
	}
	public static void setIterations(int iterations)
	{
		Data.TOTAL_ITERATIONS = iterations;		
	}
}
